SinatraとHamlとScssとCoffeeScriptでモダンなWeb制作環境を構築する #2
前回はRubyのインストールから簡単に各メタ言語の使い方を紹介させて頂きました。今回は応用編を紹介したいと思います。
コンパイルする記述を一つにまとめる
前回紹介した方法は一番シンプルな方法でした。GETリクエストとパスの組み合わせに一つのhamlファイルを紐付けているため、このままではファイルが増える毎に記述をコピペしなくてはいけません。
get '/' do haml :index end # aboutページが欲しくなったら…? get '/about' do haml :about end
これではあまりモダンなとは言いがたいですよね。というわけで記述を省略できる方法ですが、getメソッドにパスを与えている部分を正規表現にすれば実現出来ます。
要するに以下のように記述すればいいのです。
get %r{^/(.*)\.html$} do haml :"#{ params[:captures].first }" end
ひとつずつ説明していきます。
まずは正規表現でパスとマッチさせる部分ですが、パスの中に /(スラッシュ) が含まれるのは避けられないので %r{ } という記法を使っています。正規表現の囲みにスラッシュを使っていないためエスケープを省略できます。
%r{^/(.*)\.html$}
そしてこの正規表現の中身ですが、スラッシュから始まり、間を省略して、.html で終わるパスにマッチするようになっています。
この () で囲んだ部分は下のブロック内で params[:captures] という記述で取り出すことができます。しかしここで取り出せる形式は配列のため Array#first でさらに先頭の要素を取り出しています。
:"#{ params[:captures].first }"
最後にhamlメソッドにコンパイルするファイルの場所を教えているのですが、文字列ではなくシンボルという形式で渡したいので : で始まる文字列に似た記述になっています。ダブルクォートの中に #{ } で囲むことによってその位置に結果の値が展開されます。
これは他の文字列等と連結する場合に便利な記法ですので上記のように特に連結する相手がいない場合は以下のように記述することもできます。
haml params[:captures].first.to_sym
to_sym でシンボルに変換されます。
scssとcoffeescriptもまとめてみる
hamlと基本は同じと考えていいでしょう。ただ大体cssとjsを同じディレクトリに格納することは無いと思うので2つのディレクトに分けることを前提として、ファイル名と拡張子の組み合わせでコンパイルの記述を組み立てるようにしました。
get %r{^/(stylesheets|javascripts)/(.*)\.(css|js)$} do dir = params[:captures][0] == 'stylesheets' ? 'scss' : 'coffee' file = params[:captures][1] method = params[:captures][2] == 'css' ? :scss : :coffee send(method, :"#{ dir }/#{ file }") end
こちらもひとつずつ説明していきます。
まずは正規表現の部分はスラッシュで始まり、格納するディレクトリの名称が2パターン(stylesheets、javascripts)あること、その次にスラッシュで区切り、ファイルやディレクトリの部分、最後に cssかjs の拡張子という構成です。
%r{^/(stylesheets|javascripts)/(.*)\.(css|js)$}
それぞれ () で囲んだ部分は params[:captures] のインデックス0〜2に順番に入っていますので、dir file method という変数に取り出しました。
dir = params[:captures][0] == 'stylesheets' ? 'scss' : 'coffee' file = params[:captures][1] method = params[:captures][2] == 'css' ? :scss : :coffee
最後に send というRubyのメソッドで、呼び出したいメソッドを呼び出す ということをしています。sendの第二引数以降に値を渡すことで呼び出したいメソッドの引数にしてくれます。
send(method, :"#{ dir }/#{ file }") # scss :"scss/hoge" といった記述を抽象化出来る
レイアウトを切り替える
例えば管理画面を /admin 以下で作成したい場合、レイアウトを変えられるとすごく便利ですよね。そんな時は sinatra-contrib の Sinatra::Namespace というプラグインと組み合わせると簡単に記述できます。
具体的には以下の様なコードになります。
class App < Sinatra::Base register Sinatra::Namespace namespace '/admin' do get %r{^/(.*)\.html$} do haml :"admin/#{ params[:captures].first }", layout: :admin_layout end end # 先に記述したhaml用のコード get %r{^/(.*)\.html$} do haml :"#{ params[:captures].first }" end end [/ruby] <p>まずクラス定義の頭で <strong>register</strong> というメソッドを使い <strong>Sinatra::Namespaceプラグイン</strong> を登録しています。このモジュールはGemfileで <strong>gem 'sinatra-contrib', require: 'sinatra/contrib/all'</strong> としているので(<a href="/server-side/language/modern-web-creating-environment/#toc-bundlergem">前回参照</a>)特にrequire文を書く必要はありません。<br /> 次に <strong>namespace</strong> メソッドを使い <strong>/admin</strong> という括りの中で動作するようにブロックを渡し、中にgetのブロックを記述しています。<br /> hamlメソッドの引数の最後に <strong>layout: :admin_layout</strong> が渡されているところに注目してください。<br /> こうすることで <strong>views/admin_layout.haml</strong> を通常のレイアウトファイル(views/layout.haml)と切り替えてくれるようになります。</p> haml :"admin/#{ params[:captures].first }", layout: :admin_layout
しかしなんとなくこれは冗長です。getメソッドに渡している正規表現や、hamlメソッドの記述などが単なるコピペになっていまっています。
なので以下のようにリファクタリングしておきました。
class App < Sinatra::Base register Sinatra::Namespace HTML_PATTERN = %r{^/(.*)\.html$} def haml_render(file, option = {}) admin_dir = option[:admin] ? 'admin/' : '' layout = option[:admin] ? :admin_layout : :layout haml :"#{ admin_fir }#{ file }", layout: layout end namespace '/admin' do get HTML_PATTERN do haml_render params[:captures].first, admin: true end end get HTML_PATTERN do haml_render params[:captures].first end end [/ruby]
getメソッドの記述がかなりすっきりしました。cssやjsも同様の方法でadminという名前空間とそれ以外で出しわけのルールを作ることも可能だと思います。
まとめ
今回はRubyのコードをガッツリ書いて手間を省けるようにしてみました。アイデア次第でいろんなことが出来ると思うので是非自分にあったルールを作ってみてください。
現状のままだとブラウザからのリクエストがあった時にのみコンパイルするようになっていますので、次回はまとめて静的ファイルに保存出来るようにしてみたいと思います。